package com.yanqu.road.server.cmd.bag;

import com.yanqu.road.entity.config.goods.GoodsCompose;
import com.yanqu.road.entity.config.goods.GoodsInfo;
import com.yanqu.road.entity.config.skin.SkinInfo;
import com.yanqu.road.entity.enums.eGoodsType;
import com.yanqu.road.entity.enums.eLogMoneyType;
import com.yanqu.road.message.YanQuMessage;
import com.yanqu.road.pb.bag.BagProto;
import com.yanqu.road.server.cmd.base.AbstractCommand;
import com.yanqu.road.server.command.Cmd;
import com.yanqu.road.server.gameplayer.GamePlayer;
import com.yanqu.road.server.gameplayer.module.player.BagModule;
import com.yanqu.road.server.gameplayer.module.player.CurrencyModule;
import com.yanqu.road.server.manger.config.GoodsMgr;
import com.yanqu.road.server.manger.config.SkinMgr;
import com.yanqu.road.server.protocol.GameErrorCode;
import com.yanqu.road.server.protocol.Protocol;
import com.yanqu.road.utils.property.Property;

import java.math.BigInteger;
import java.util.List;
import java.util.Map;

@Cmd(code = Protocol.S_BAG_COMPOSE, desc = "道具合成")
public class GoodsCompositeCmd extends AbstractCommand {

    private int composeGoodsId;

    private long count;

    private int type; // 合成类型

    private List<BagProto.BagTempMsg> items; // 混合合成的道具列表

    @Override
    public boolean parseData(YanQuMessage packet) throws Exception {
        BagProto.BagComposeReqMsg reqMsg = BagProto.BagComposeReqMsg.parseFrom(packet.getBytes());
        composeGoodsId = reqMsg.getGoodsId();
        count = reqMsg.getCount();
        type = reqMsg.getType();
        items = reqMsg.getItemList();
        if (0 == count) {
            count = 1L;
        }
        return true;
    }

    @Override
    public void execute(GamePlayer player, YanQuMessage packet) throws Exception {
        GoodsCompose goodsCompose = GoodsMgr.getGoodsCompose(composeGoodsId);
        if (null == goodsCompose) {
            ret = GameErrorCode.E_BAG_GOODS_COMPOSE_NO_FOUND;
            return;
        }

        Property consumeProperty = new Property();
        for (Map.Entry<Integer, BigInteger> entry : goodsCompose.getConsume().getGoods().entrySet()) {
            consumeProperty.addProperty(entry.getKey(), entry.getValue().multiply(BigInteger.valueOf(count)));
        }

        if (type != 0) { // 特殊的合成类型
            if (type == eComposeType.PeerlessSkin.getValue()) {
                SkinInfo skinInfo = SkinMgr.getSkinInfo(composeGoodsId);
                if (skinInfo == null) {
                    ret = GameErrorCode.E_SKIN_NOT_EXIST;
                    return;
                }

                if (skinInfo.getIsSpecialExc() == 0) {
                    ret = GameErrorCode.E_BAG_GOODS_COMPOSE_ERROR;
                    return;
                }
            }

            consumeProperty = getMixedComposeProperty(player, consumeProperty);
            if (consumeProperty == null) {
                ret = GameErrorCode.E_BAG_GOODS_COMPOSE_ERROR;
                return;
            }
        }

        if (consumeProperty.getGoods().size() <= 0) {
            ret = GameErrorCode.E_BAG_GOODS_COMPOSE_ERROR;
            return;
        }
        long beginTime = System.currentTimeMillis();
        if (player.getModule(CurrencyModule.class).removeCurrency(consumeProperty, eLogMoneyType.Bag, eLogMoneyType.BagComposite)) {//扣除合成材料
            // 增加合成道具
            player.getModule(CurrencyModule.class).addCurrency(new Property(goodsCompose.getGoodsId(), BigInteger.valueOf(count)),
                    eLogMoneyType.Bag, eLogMoneyType.BagComposite);
            ret = 0;
        } else {
            ret = GameErrorCode.E_BAG_ITEM_NO_ENOUGH;
        }
        log.info("compose goods cost:{} millis", System.currentTimeMillis() - beginTime);
    }

    /**
     * 获取混合合成需要消耗的道具数量
     *
     * @param player          玩家
     * @param consumeProperty 合成消耗
     * @return Property
     */
    private Property getMixedComposeProperty(GamePlayer player, Property consumeProperty) {
        int mainGoodsId = 0; // 主要合成的道具材料ID，目前都是由一样物品的碎片合成它本身
        long mainGoodsNum = 0;
        long cnt = 0; // 道具合成总数
        Map<Integer, BigInteger> goods = consumeProperty.getGoods();
        Property res = new Property();

        for (BagProto.BagTempMsg item : items) {
            int goodsId = item.getGoodsId();
            long num = item.getNum();
            if (goods.containsKey(goodsId) || canReplace(type, goodsId)) {
                if (goods.containsKey(goodsId)) { // 合成消耗直接包含的道具就是碎片
                    mainGoodsId = goodsId;
                    mainGoodsNum = num;
                }
                cnt += num;
                if (num > 0) { // 防止扣除道具失败
                    res.addProperty(goodsId, num);
                }
            }
        }

        if (type == eComposeType.PeerlessSkin.getValue()) { // 需要优先消耗背包的原始皮肤碎片
            long userBagItemCount = player.getModule(BagModule.class).getUserBagItemCount(mainGoodsId);
            if (userBagItemCount != mainGoodsNum) {
                return null;
            }
        }

        if (goods.containsKey(mainGoodsId)) {
            long total = goods.get(mainGoodsId).longValue(); // 需要消耗的总数量
            if (cnt != total) { // 不管比需要消耗的道具多了还是少了，不合成
                return null;
            }
        } else {
            return null;
        }

        return res; // 将客户端发来的合成内容作为最终需要消耗的材料
    }

    /**
     * 判断在该种合成类型下，该道具是否能成为替换品
     *
     * @param type    道具ID
     * @param goodsId 合成类型
     * @return boolean
     */
    private boolean canReplace(int type, int goodsId) {
        GoodsInfo goodsInfo = GoodsMgr.getGoodsById(goodsId);
        if (type == eComposeType.PeerlessSkin.getValue() && goodsInfo.getType() == eGoodsType.PeerlessSkinPiece.getValue()) {
            return true;
        }

        return false;
    }

    @Override
    public void sendData(GamePlayer player) {
        BagProto.BagComposeRespMsg.Builder respMsg = BagProto.BagComposeRespMsg.newBuilder();
        respMsg.setRet(ret);
        if (0 == ret) {
            respMsg.setComposeGoodsId(composeGoodsId);
            respMsg.setComposeCount(count);
        }
        player.sendPacket(Protocol.U_BAG_COMPOSE, respMsg);
    }
}
